#include "main.h"
// 读取芯片ID
// 返回值如下:
// 0XEF13,表示芯片型号为W25Q80
// 0XEF14,表示芯片型号为W25Q16
// 0XEF15,表示芯片型号为W25Q32
// 0XEF16,表示芯片型号为W25Q64
// 0XEF17,表示芯片型号为W25Q128
// 读取设备ID
uint16_t W25Q64_readID(void)
{
    uint16_t temp = 0;
    // 将CS端拉低为低电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);
    // 发送指令90h
    spi_read_write_byte(0x90); // 发送读取ID命令
    // 发送地址  000000H
    spi_read_write_byte(0x00);
    spi_read_write_byte(0x00);
    spi_read_write_byte(0x00);

    // 接收数据
    // 接收制造商ID
    temp |= spi_read_write_byte(0xFF) << 8;
    // 接收设备ID
    temp |= spi_read_write_byte(0xFF);
    // 恢复CS端为高电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, SET);
    // 返回ID
    return temp;
}
// 发送写使能
void W25Q64_write_enable(void)
{
    // 拉低CS端为低电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);
    // 发送指令06h
    spi_read_write_byte(0x06);
    // 拉高CS端为高电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, SET);
}
void W25Q64_wait_busy(void)
{
    unsigned char byte = 0;
    do
    {
        // 拉低CS端为低电平
        gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);
        // 发送指令05h
        spi_read_write_byte(0x05);
        // 接收状态寄存器值
        byte = spi_read_write_byte(0Xff);
        // 恢复CS端为高电平
        gpio_bit_write(GPIOF, GPIO_PIN_6, SET);
        // 判断BUSY位是否为1 如果为1说明在忙，重新读写BUSY位直到为0
    } while ((byte & 0x01) == 1);
}
/**********************************************************
 * 函 数 名 称：W25Q64_erase_sector
 * 函 数 功 能：擦除一个扇区
 * 传 入 参 数：addr=擦除的扇区号
 * 函 数 返 回：无
 * 作       者：LC
 * 备       注：addr=擦除的扇区号，范围=0~15
 **********************************************************/
void W25Q64_erase_sector(uint32_t addr)
{
    // 计算扇区号，一个扇区4KB=4096
    addr *= 4096;
    W25Q64_write_enable(); // 写使能
    W25Q64_wait_busy();    // 判断忙，如果忙则一直等待
    // 拉低CS端为低电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);
    // 发送指令20h
    spi_read_write_byte(0x20);
    // 发送24位扇区地址的高8位
    spi_read_write_byte((uint8_t)((addr) >> 16));
    // 发送24位扇区地址的中8位
    spi_read_write_byte((uint8_t)((addr) >> 8));
    // 发送24位扇区地址的低8位
    spi_read_write_byte((uint8_t)addr);
    // 恢复CS端为高电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, SET);
    // 等待擦除完成
    W25Q64_wait_busy();
}
/**********************************************************
 * 函 数 名 称：W25Q64_write
 * 函 数 功 能：写数据到W25Q64进行保存
 * 传 入 参 数：buffer=写入的数据内容        addr=写入地址        numbyte=写入数据的长度
 * 函 数 返 回：无
 * 作       者：LC
 * 备       注：无
 **********************************************************/
void W25Q64_write(uint8_t *buffer, uint32_t addr, uint16_t numbyte)
{
    unsigned int i = 0;
    // 擦除扇区数据
    W25Q64_erase_sector(addr / 4096);
    // 写使能
    W25Q64_write_enable();
    // 忙检测
    W25Q64_wait_busy();
    // 写入数据
    // 拉低CS端为低电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);
    // 发送指令02h
    spi_read_write_byte(0x02);
    // 发送写入的24位地址中的高8位
    spi_read_write_byte((uint8_t)((addr) >> 16));
    // 发送写入的24位地址中的中8位
    spi_read_write_byte((uint8_t)((addr) >> 8));
    // 发送写入的24位地址中的低8位
    spi_read_write_byte((uint8_t)addr);
    // 根据写入的字节长度连续写入数据buffer
    for (i = 0; i < numbyte; i++)
    {
        spi_read_write_byte(buffer[i]);
    }
    // 恢复CS端为高电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, SET);
    // 忙检测
    W25Q64_wait_busy();
}
/**********************************************************
 * 函 数 名 称：W25Q64_read
 * 函 数 功 能：读取W25Q64的数据
 * 传 入 参 数：buffer=读出数据的保存地址  read_addr=读取地址   read_length=读去长度
 * 函 数 返 回：无
 * 作       者：LC
 * 备       注：无
 **********************************************************/
void W25Q64_read(uint8_t *buffer, uint32_t read_addr, uint16_t read_length)
{
    uint16_t i;
    // 拉低CS端为低电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, RESET);
    // 发送指令03h
    spi_read_write_byte(0x03);
    // 发送24位读取数据地址的高8位
    spi_read_write_byte((uint8_t)((read_addr) >> 16));
    // 发送24位读取数据地址的中8位
    spi_read_write_byte((uint8_t)((read_addr) >> 8));
    // 发送24位读取数据地址的低8位
    spi_read_write_byte((uint8_t)read_addr);
    // 根据读取长度读取出地址保存到buffer中
    for (i = 0; i < read_length; i++)
    {
        buffer[i] = spi_read_write_byte(0XFF);
    }
    // 恢复CS端为高电平
    gpio_bit_write(GPIOF, GPIO_PIN_6, SET);
}
